"use strict";
//命名空间
namespace Reg {
    //模板引擎正则匹配{{ ... }}
    export const templateRegExpDouble: RegExp = /\{\{(.+?)\}\}/g;
    //模板引擎正则匹配[[ ... ]]
    export const templateRegExpOnce: RegExp = /\[\[(.+?)\]\]/g;
    //大写字母匹配
    export const upCase: RegExp =  /^[A-Z]+$/g;
    //去除空格
    export const delSpace: RegExp = /\s+/g;
}
namespace Validation {
    //ajax接口继承
    export interface AjaxInterface {
        openAjax(           //启用ajax
            method: string, //调用方式GET,POST
            url: string,    //接口地址
            data: Object    //调用请求参数
        ): any;
    }
    //Table组件参数接口
    export interface TableDataHeader {
        classSelector: string,   //样式分割器
        data: Array<any>      //table header头部数据
    }
    export interface TableData {
        selector: string,               //选择器
        styleUrl: string,               //样式调用
        htmlUrl: string,                //html地址
        controller(vm:Object): any      //控制器
    }
    //viewModel
    export interface viewModel {
        header: any,
        body: any,
        _cleanWatch: any,
        page: any,
        filter: any
    }
    const domModule = "";
}
//逻辑开始
((win)=>{
  //Oject兼容性
  if(!Object.hasOwnProperty("is")){
    Object.is = (a,b) => {
      if(a !== b){
        return false;
      }
      else{
        return true;
      }
    };
  }
    //ajax
    class Ajax implements Validation.AjaxInterface{
        //缓存
        static cache: Array<Object> = [];
        //ajax逻辑
        openAjax(method: string,url: string,data: Object):any{
            data = data || null;
            const responseStream: any = Rx.Observable.create((observer):void => {
                const xhr: XMLHttpRequest = new XMLHttpRequest;
                xhr.open(method,`${ url }?_=${ Math.random() }`,true);
                xhr.onload = () => {
                    observer.next({
                        dom: xhr.responseText,
                        url: url
                    });
                };
                xhr.onerror = () => {
                    console.error(`${ url }请求失败`);
                };
                xhr.send(data);
            }).do((dom)=>{
                //写入缓存
                //TODO: 这里没完成
                // Ajax.cache.push(JSON.parse(`{"url": "${ dom.url }","dom": "${ dom.dom }"}`));
            });
            return responseStream;
        }
    }

    //组件table
    class TzbTable extends Ajax{
        public headerDOM: HTMLElement = document.createElement("thead");
        public bodyDOM: HTMLElement = document.createElement("tbody");
        public tableDOM: HTMLElement = document.createElement("table");
        public template: string;
        public obv: any;
        public cleanNode: boolean = false;
        public trHash: string = `tr-${ Math.random().toString().replace(".","") }`;
        public watchArray: Array<any> = [];
        public bindOnceArray: Array<any> = [];
        public RegArray: Array<any>;
        public bindOnce: Array<any>;
        public clean: boolean = false;
        public viewModel: Validation.viewModel = {
            header: null,
            body: null,
            page: null,
            filter: null,
            //清空watch列表刷新表格
            _cleanWatch: () => {
                this.cleanNode = true;
                this.RegArray = null;
                this.bindOnce = null;
                this.watchArray = [];
                this.bindOnceArray = [];
            }
        };
        //根据数组获取对象索引值
        static getObjectData = (obj: Object,pro: any): any => {
            let cacheObj: Object;
            pro.object.forEach((data: string): any => {
                if(!cacheObj){
                    cacheObj = obj[data];
                }
                else{
                    if(Object.is("[object object]",Object.prototype.toString.call(cacheObj).toLowerCase())){
                        cacheObj = cacheObj[data];
                    }
                }
            });
            //深度克隆
            return cacheObj;
        };
        constructor(
            public TableData: Validation.TableData
        ){
            super();
            //运行控制器
            //默认加载TableData.htmlUrl
            if(TableData.htmlUrl){
                this.obv = (<any>this).openAjax("GET",TableData.htmlUrl);
            }
            else if(TableData.htmlNodeList){
                this.obv = this._createJsonHtml(TableData.htmlNodeList);
            }
            else{
                this.obv = "";
            }
            this._controller();
        }
        //写入DOM
        //TODO：这里需要修改
        _domWriter(data: HTMLElement): void{
            document.querySelector(this.TableData.selector).appendChild(data);
        }
        //创建json dom
        _createJsonHtml(data: Array<Object>): string{
            let tr: HTMLElement = document.createElement("tr");
            data.forEach((d: any) => {
                let td: any = document.createElement("td");
                td.innerHTML = d.data;
                Object.keys(d.attr).forEach((attr: string,index: number) => {
                    if(attr === "className"){
                        td.setAttribute("class",d.attr[attr]);
                    }
                    else{
                        let newAttr = attr.split("").map((addStr: string) => {
                            if(Reg.upCase.test(addStr)){
                                return `-${ addStr.toLowerCase() }`;
                            }
                            else{
                                return addStr;
                            }
                        });
                        td.setAttribute(newAttr.join(""), d.attr[attr]);
                    }
                    tr.appendChild(td);
                });
            });
            let readom: string = Math.random().toString().replace(".","");
            let div: HTMLElement = document.createElement("div");
            div.id = readom;
            div.appendChild(tr);
            return Rx.Observable.of({
                dom: div.innerHTML,
                url: readom
            });
        }
        //初始化样式选择器
        _initHeaderStyleSekector(): void{
            if(!this.viewModel.header.classSelector){
                this.viewModel.header.classSelector = ":";
            }
        }
        //完成thead构建
        _tHead(): void{
            if(this.viewModel.header && this.viewModel.header.hasOwnProperty("data")){
                let dom = this.viewModel.header.data.reduce((data: string,origin: string): string => {
                    const domNode = origin.split(this.viewModel.header.classSelector);
                    return data + `<th class="${ domNode[1] }">${ domNode[0] }</th>`;
                },"");
                this.headerDOM.innerHTML = dom;
                this.tableDOM.appendChild(this.headerDOM);
            }
        }
        //完成脏检测列表构建
        _creatWatchList(data: any): void{
            //刚刚创建表格的逻辑
            if(!this.RegArray){
                //创建翻页
                this._page();
                //获取模板数据
                //单项绑定
                console.log(data)
                let bindOnce: Array<any> = data.dom.match(Reg.templateRegExpOnce);
                this.bindOnce = bindOnce.map((data: string): any => {
                    return {
                        name: data,
                        object: data.replace("[[","").replace("]]","").replace(Reg.delSpace,"").split(".")
                    };
                });
                //双向绑定
                let RegArray: Array<any> = data.dom.match(Reg.templateRegExpDouble);
                this.RegArray = RegArray.map((data: string): any => {
                    //提取过滤器
                    let objectData: string = data;
                    let filter: any;
                    let filterPro: Array<string>;
                    if(data.indexOf("|") != -1){
                        filterPro = data.split("|");
                        objectData = `${ filterPro[0] } }}`;
                    }
                    if(this.viewModel && this.viewModel.filter && data.indexOf("|") != -1){
                        filter = this.viewModel.filter[filterPro[1].replace("}}","").replace(Reg.delSpace,"")];
                    }
                    return {
                        filter: filter,
                        name: data,
                        object: objectData.replace("{{","").replace("}}","").replace(Reg.delSpace,"").split(".")
                    };
                });
                //创建watch列表
                if(this.viewModel.body && (<any>this.viewModel.body).hasOwnProperty("data")){
                    (<any>this.viewModel.body).data.forEach((TableDataIndex) => {
                        let listDataRegArray: Array<any> = [];
                        //从模板列表里填充数据
                        //双向绑定数据
                        this.RegArray.forEach((RegArrayIndex) => {
                            //重要需要把Object类型指向改变不然无法引用改变数据
                            RegArrayIndex = Object.create(RegArrayIndex);
                            if(Object.is("[object function]",Object.prototype.toString.call(RegArrayIndex.filter).toLowerCase())){
                                RegArrayIndex.data = RegArrayIndex.filter(TzbTable.getObjectData(TableDataIndex,RegArrayIndex));
                            }
                            else{
                                RegArrayIndex.data = TzbTable.getObjectData(TableDataIndex,RegArrayIndex);
                            }
                            RegArrayIndex.hash = `td-${ Math.random().toString().replace(".","") }`;
                            listDataRegArray.push(RegArrayIndex);
                        });
                        this.watchArray.push(listDataRegArray);
                        //单绑数据
                        let listDataBindOnce: Array<any> = [];
                        this.bindOnce.forEach((bindOnceIndex) => {
                            //重要需要把Object类型指向改变不然无法引用改变数据
                            bindOnceIndex = Object.create(bindOnceIndex);
                            bindOnceIndex.data = TzbTable.getObjectData(TableDataIndex,bindOnceIndex);
                            listDataBindOnce.push(bindOnceIndex);
                        });
                        this.bindOnceArray.push(listDataBindOnce);
                    });
                }
            }
            //创建完表格的逻辑
            else{
                //修改watch列表
                if(this.viewModel.body && (<any>this.viewModel.body).hasOwnProperty("data")){
                    (<any>this.viewModel.body).data.forEach((TableDataIndex,dataIndex) => {
                        //从模板列表里填充数据
                        this.RegArray.forEach((RegArrayIndex,RegIndex) => {
                            // 对比watch列表数据(只更新不一样的数据)
                            let newData = TzbTable.getObjectData(TableDataIndex,RegArrayIndex);
                            if(Object.is("[object function]",Object.prototype.toString.call(this.watchArray[dataIndex][RegIndex].filter).toLowerCase())){
                                newData = this.watchArray[dataIndex][RegIndex].filter(newData);
                            }
                            if(!Object.is(this.watchArray[dataIndex][RegIndex].data,newData)){
                                this.watchArray[dataIndex][RegIndex].data = newData;
                                document.querySelector(`.${ this.watchArray[dataIndex][RegIndex].hash }`).innerHTML = newData;
                            }
                        });
                    });
                }
            }
        }
        //creatTbody
        _creatTbable(): void{
            this._domWriter(this.tableDOM);
        }
        //构件tbody(这里只运行一次)
        _tBody(): void{
            //判断是否要完全更新dom
            if(this.cleanNode){
                this.cleanNode = false;
                Array.prototype.slice.call(document.querySelectorAll(`.${ this.trHash }`)).forEach((dom: HTMLElement) => {
                  dom.outerHTML = "";
                });
            }
            this.watchArray.forEach((data,indexWatch) => {
                let dom: string = (<any>this.template).dom;
                data.forEach((dataIndex,indexData) => {
                    if(this.bindOnceArray[indexWatch][indexData]){
                        dom = dom.replace(this.bindOnceArray[indexWatch][indexData].name,this.bindOnceArray[indexWatch][indexData].data);
                    }
                    dom = dom.replace(dataIndex.name,`<td-data class="${ dataIndex.hash }">${ dataIndex.data }</td-data>`);
                });
                dom.replace("<tr>","").replace("</tr>","");
                let tr: HTMLElement = document.createElement("tr");
                tr.className = this.trHash;
                tr.innerHTML = dom;
                this.bodyDOM.appendChild(tr);
            });
            this.tableDOM.appendChild(this.bodyDOM);
        }
        //脏检查
        _differ(newValue): void{
            this._creatWatchList(this.template);
        }
        //控制器绑定
        _controller(): void{
            const _that = this;
            //双向绑定设置
            Object.defineProperty(this.viewModel,"header",{
                set: function(newValue){
                    this._newValueHeader = newValue;
                    //写入头部(头部不做hash双向绑定)
                    if(_that.viewModel.header && _that.viewModel.header.data){
                        _that._initHeaderStyleSekector();
                        _that._tHead();
                        _that._creatTbable();
                    }
                },
                get: function(){
                    return this._newValueHeader;
                }
            });
            //观察模板加载完毕
            _that.obv.subscribe((data: any) => {
                Object.defineProperty(this.viewModel,"body",{
                    set: function(newValue){
                        this._newValueBody = newValue;
                        //加载HTML完成watch列表
                        if(_that.watchArray.length === 0){
                            //写入body
                            _that.template = data;
                            _that._creatWatchList(data);
                            _that._tBody();
                        }
                        else{
                            //运行脏检测
                            _that._differ(newValue);
                        }
                    },
                    get: function() {
                        return this._newValueBody;
                    }
                });
            });
            //分页隐藏显示
            Object.defineProperty(this.viewModel,"_pageShow",{
                set: function(newValue){
                    this._newPageShow = newValue;
                    if(newValue){
                        (<any>document.querySelector(`${ _that.TableData.selector }-page`)).style.display = "block";
                    }
                    else{
                        (<any>document.querySelector(`${ _that.TableData.selector }-page`)).style.display = "none";
                    }
                },
                get: function() {
                    return this._newPageShow;
                }
            });
            //增加viewModel
            this.TableData.controller(this.viewModel);
        }
        //翻页
        _page(): void{
            let dom = document.querySelector(`${ this.TableData.selector }-page`);
            dom.innerHTML = `
                <button id="up-page-${ this.TableData.selector }">上翻页</botton>
                <button id="down-page-${ this.TableData.selector }">下翻页</botton>
            `;
            document.querySelector(`#up-page-${ this.TableData.selector }`).onclick = (): void => {
                if(this.viewModel && this.viewModel.page && this.viewModel.page.pageUp){
                    this.viewModel.page.pageUp(this.viewModel);
                }
            };
            document.querySelector(`#down-page-${ this.TableData.selector }`).onclick = (): void => {
                if(this.viewModel && this.viewModel.page && this.viewModel.page.pageDown){
                    this.viewModel.page.pageDown(this.viewModel);
                }
            };
        }
    };
    win.TzbTable = TzbTable;
})(Function("return this")());
